package juc.aqs;

import sun.misc.Unsafe;

import java.util.concurrent.locks.LockSupport;

/**
 * 手写AQS:cas+同步队列+条件队列
 */
public abstract class AQS {

    /**
     * 独占线程
     */
    private Thread exclusiveOwnerThread;

    /**
     * 状态
     */
    private volatile int state;

    /**
     * 头节点
     */
    private volatile Node head;
    /**
     * 尾节点
     */
    private volatile Node tail;


    abstract boolean tryAcquire(int arg);

    /**
     * 1.cas获取锁
     * 2.获取失败放入队列中并阻塞线程
     *
     * @param arg
     * @return
     */
    public boolean acquire(int arg) {
        // cas
        if (tryAcquire(arg)) {
            return true;
        }
        // 入队
        Node node = enq();
        return park(arg, node);
    }

    /**
     * 1.阻塞线程
     * 2.线程被唤醒后就尝试获取锁
     *
     * @param arg
     * @param node
     * @return
     */
    private boolean park(int arg, Node node) {
        for (; ; ) {
            // 尝试获取锁
            Node pre = node.pre;
            if (pre == head && tryAcquire(arg)) {
                // 获取锁成功后出队
                setHead(node);
                pre.next = null;
                return true;
            }
            // 阻塞线程
            LockSupport.park(Thread.currentThread());
        }
    }

    private void setHead(Node node) {
        head = node;
        node.thread = null;
        node.pre = null;
    }

    abstract boolean tryRelease(int arg);


    /**
     * 释放锁
     * 1.释放锁
     * 2.唤醒第一个等待的线程
     *
     * @param arg
     */
    public void release(int arg) {
        // 释放锁
        if (tryRelease(arg)) {
            // 唤醒第一个等待的线程
            Node oldNode = head;
            if (oldNode != null && oldNode.next != null) {
                Node newHead = oldNode.next;
                // 唤醒线程
                unPark(newHead.thread);
            }
        }
    }

    private static void unPark(Thread thread) {
        if (thread != null) {
            LockSupport.unpark(thread);
        }
    }

    /**
     * cas 入队
     *
     * @return
     */
    private Node enq() {
        for (; ; ) {
            // 设置队头
            if (head == null) {
                addHead();
            }
            // 加入队尾
            if (tail != null) {
                Node node = new Node();
                node.thread = Thread.currentThread();
                Node oldTail = tail;
                node.pre = oldTail;
                if (tailCas(oldTail, node)) {
                    oldTail.next = node;
                    return node;
                }
            }
        }
    }

    private void addHead() {
        Node node = new Node();
        if (headCas(null, node)) {
            tail = head;
        }
    }

    // ------------------cas相关------------------

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long stateOffset;
    private static final long headOffset;
    private static final long tailOffset;

    static {
        try {
            stateOffset = unsafe.objectFieldOffset
                    (AQS.class.getDeclaredField("state"));
            headOffset = unsafe.objectFieldOffset
                    (AQS.class.getDeclaredField("head"));
            tailOffset = unsafe.objectFieldOffset
                    (AQS.class.getDeclaredField("tail"));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected boolean stateCas(int old, int newValue) {
        return unsafe.compareAndSwapInt(this, stateOffset, old, newValue);
    }

    private boolean headCas(Node old, Node newValue) {
        return unsafe.compareAndSwapObject(this, headOffset, old, newValue);
    }

    private boolean tailCas(Node old, Node newValue) {
        return unsafe.compareAndSwapObject(this, tailOffset, old, newValue);
    }

    // ------------------------------------

    protected int getState() {
        return state;
    }

    protected void setState(int state) {
        this.state = state;
    }


    public Thread getExclusiveOwnerThread() {
        return exclusiveOwnerThread;
    }

    public void setExclusiveOwnerThread(Thread exclusiveOwnerThread) {
        this.exclusiveOwnerThread = exclusiveOwnerThread;
    }


    /**
     * 节点信息,双向链表实现
     */

    static class Node {
        /**
         * 状态
         */
        private volatile int waitStatus;

        /**
         * 线程
         */
        private Thread thread;

        /**
         * 上一个节点
         */
        private volatile Node pre;
        /**
         * 下一个节点
         */
        private volatile Node next;

        // 可以唤醒下一个节点
        static final int SIGNAL = -1;

        public int getWaitStatus() {
            return waitStatus;
        }

        public void setWaitStatus(int waitStatus) {
            this.waitStatus = waitStatus;
        }

        public Thread getThread() {
            return thread;
        }

        public void setThread(Thread thread) {
            this.thread = thread;
        }

        public Node getPre() {
            return pre;
        }

        public void setPre(Node pre) {
            this.pre = pre;
        }

        public Node getNext() {
            return next;
        }

        public void setNext(Node next) {
            this.next = next;
        }

    }


}
